function init(elemid) {
    // 获取canvas元素
    let canvas = document.getElementById(elemid)
    // 获取2d绘图上下文,这里d是小写的
    c = canvas.getContext('2d')
    // 设置canvas的宽度为窗口内宽度，高度为窗口内高度
    w = (canvas.width = window.innerWidth)
    h = (canvas.height = window.innerHeight)
    // 设置填充样式为半透明黑
    c.fillStyle = "rgba(30,30,30,1)"
    // 使用填充样式填充整个canvas
    c.fillRect(0, 0, w, h)
    // 返回绘图上下文和canvas元素
    return { c: c, canvas: canvas }
}

function dist(p1x, p1y, p2x, p2y) {
    return Math.sqrt(Math.pow(p2x - p1x, 2) + Math.pow(p2y - p1y, 2))
}

export class segment {
    // 构造函数，用于初始化 segment 对象
    constructor(parent, l, a, first) {
        // 如果是第一条触手段，则位置坐标为触手顶部位置
        // 否则位置坐标为上一个segment对象的nextPos坐标
        this.first = first
        if (first) {
            this.pos = {
                x: parent.x,
                y: parent.y,
            }
        } else {
            this.pos = {
                x: parent.nextPos.x,
                y: parent.nextPos.y,
            }
        }
        // 设置segment的长度和角度
        this.l = l
        this.ang = a
        // 计算下一个segment的坐标位置
        this.nextPos = {
            x: this.pos.x + this.l * Math.cos(this.ang),
            y: this.pos.y + this.l * Math.sin(this.ang),
        }
    }
    // 更新segment位置的方法
    update(t) {
        // 计算segment与目标点的角度
        this.ang = Math.atan2(t.y - this.pos.y, t.x - this.pos.x)
        // 根据目标点和角度更新位置坐标
        this.pos.x = t.x + this.l * Math.cos(this.ang - Math.PI)
        this.pos.y = t.y + this.l * Math.sin(this.ang - Math.PI)
        // 根据新的位置坐标更新nextPos坐标
        this.nextPos.x = this.pos.x + this.l * Math.cos(this.ang)
        this.nextPos.y = this.pos.y + this.l * Math.sin(this.ang)
    }
    // 将 segment 回执回初始位置的方法
    fallback(t) {
        // 将位置坐标设置为目标点坐标
        this.pos.x = t.x
        this.pos.y = t.y
        this.nextPos.x = this.pos.x + this.l * Math.cos(this.ang)
        this.nextPos.y = this.pos.y + this.l * Math.sin(this.ang)
    }
    show() {
        c.lineTo(this.nextPos.x, this.nextPos.y)
    }
}

// 定义 tentacle 类
export class tentacle {
    // 构造函数，用于初始化 tentacle 对象
    constructor(x, y, l, n, a) {
        // 设置触手的顶部位置坐标
        this.x = x
        this.y = y
        // 设置触手的长度
        this.l = l
        // 设置触手的段数
        this.n = n
        // 初始化触手的目标点对象
        this.t = {}
        // 设置触手的随机移动参数
        this.rand = Math.random()
        // 创建触手的第一条段
        this.segments = [new segment(this, this.l / this.n, 0, true)]
        // 创建其他的段
        for (let i = 1; i < this.n; i++) {
            this.segments.push(
                new segment(this.segments[i - 1], this.l / this.n, 0, false)
            )
        }
    }
    // 移动触手到目标点的方法
    move(last_target, target) {
        // 计算触手顶部与目标点的角度
        this.angle = Math.atan2(target.y - this.y, target.x - this.x)
        // 计算触手的距离参数
        this.dt = dist(last_target.x, last_target.y, target.x, target.y)
        // 计算触手的目标点坐标
        this.t = {
            x: target.x - 0.8 * this.dt * Math.cos(this.angle),
            y: target.y - 0.8 * this.dt * Math.sin(this.angle)
        }
        // 如果计算出了目标点，则更新最后一个segment对象的位置坐标
        // 否则，更新最后一个segment对象的位置坐标为目标点坐标
        if (this.t.x) {
            this.segments[this.n - 1].update(this.t)
        } else {
            this.segments[this.n - 1].update(target)
        }
        // 遍历所有segment对象，更新它们的位置坐标
        for (let i = this.n - 2; i >= 0; i--) {
            this.segments[i].update(this.segments[i + 1].pos)
        }
        if (
            dist(this.x, this.y, target.x, target.y) <=
            this.l + dist(last_target.x, last_target.y, target.x, target.y)
        ) {
            this.segments[0].fallback({ x: this.x, y: this.y })
            for (let i = 1; i < this.n; i++) {
                this.segments[i].fallback(this.segments[i - 1].nextPos)
            }
        }
    }
    show(target) {
        // 如果触手与目标点的距离小于触手的长度，则回执触手
        if (dist(this.x, this.y, target.x, target.y) <= this.l) {
            // 设置全局合成操作为lighter
            c.globalCompositeOperation = "lighter"
            // 开始新路径
            c.beginPath()
            // 从触手起始位置开始绘制线条
            c.moveTo(this.x, this.y)
            // 遍历所有的segment对象，并使用他们的show方法回执线条
            for (let i = 0; i < this.n; i++) {
                this.segments[i].show()
            }
            // 设置线条样式
            c.strokeStyle = "hsl(" + (this.rand * 60 + 180) +
                ",100%," + (this.rand * 60 + 25) + "%)"
            // 设置线条宽度
            c.lineWidth = this.rand * 2
            // 设置线条端点样式
            c.lineCap = "round"
            // 设置线条连接处样式
            c.lineJoin = "round"
            // 绘制线条
            c.stroke()
            // 设置全局合成操作为“source-over”
            c.globalCompositeOperation = "source-over"
        }
    }
    // 绘制触手的圆形头的方法
    show2(target) {
        // 开始新路径
        c.beginPath()
        // 如果触手与目标点的距离小于触手的长度，则回执白色的圆形
        // 否则绘制青色的圆形
        if (dist(this.x, this.y, target.x, target.y) <= this.l) {
            c.arc(this.x, this.y, 2 * this.rand + 1, 0, 2 * Math.PI)
            c.fillStyle = "whith"
        } else {
            c.arc(this.x, this.y, this.rand * 2, 0, 2 * Math.PI)
            c.fillStyle = "darkcyan"
        }
        // 填充圆形
        c.fill()
    }
}
